package com.ershijin.resourceserver.config;

import com.ershijin.common.CustomizerGrantedAuthority;
import com.ershijin.common.CustomizerOAuth2AuthenticatedPrincipal;
import com.ershijin.common.util.JsonUtils;
import com.ershijin.common.util.RedisUtils;
import net.minidev.json.JSONArray;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.oauth2.core.DefaultOAuth2AuthenticatedPrincipal;
import org.springframework.security.oauth2.core.OAuth2AuthenticatedPrincipal;
import org.springframework.security.oauth2.core.oidc.IdTokenClaimNames;
import org.springframework.security.oauth2.server.resource.introspection.NimbusOpaqueTokenIntrospector;

import java.time.Instant;
import java.util.Collection;
import java.util.Map;
import java.util.stream.Collectors;

public class CachingOpaqueTokenIntrospector extends NimbusOpaqueTokenIntrospector {

    public CachingOpaqueTokenIntrospector(String introspectionUri, String clientId, String clientSecret) {
        super(introspectionUri, clientId, clientSecret);
    }

    @Override
    public OAuth2AuthenticatedPrincipal introspect(String token) {

        String tokenKey = "token:" + token;

        String jsonPrincipal = (String) RedisUtils.get(tokenKey);
        if (ObjectUtils.isNotEmpty(jsonPrincipal)) {
            return JsonUtils.toObject(jsonPrincipal, CustomizerOAuth2AuthenticatedPrincipal.class);
        }

        OAuth2AuthenticatedPrincipal introspect = super.introspect(token);

        CustomizerOAuth2AuthenticatedPrincipal customizerOAuth2AuthenticatedPrincipal = new CustomizerOAuth2AuthenticatedPrincipal();
        customizerOAuth2AuthenticatedPrincipal.setName(introspect.getName());
        customizerOAuth2AuthenticatedPrincipal.setAttributes(introspect.getAttributes());
        customizerOAuth2AuthenticatedPrincipal.setAuthorities(((JSONArray) introspect.getAttribute("authorities")).stream().map(o -> new CustomizerGrantedAuthority(o.toString())).collect(Collectors.toSet()));

        Instant tokenExpired = customizerOAuth2AuthenticatedPrincipal.getAttribute(IdTokenClaimNames.EXP);// 过期时间
        long cacheTime = tokenExpired.getEpochSecond() - Instant.now().getEpochSecond();
        if (cacheTime > 0) {
            RedisUtils.set(tokenKey, JsonUtils.toJsonString(customizerOAuth2AuthenticatedPrincipal), cacheTime);
        }

        return customizerOAuth2AuthenticatedPrincipal;
    }
}
